﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Rud.Holmgren.TabulexLib.Common;

namespace Rud.Holmgren.TabulexLib
{
    public class TbxClient
    {
        private string username, password;
        private TbxWebserviceClient client = new TbxWebserviceClient();

        public TbxClient(string username, string password)
        {
            this.username = username;
            this.password = password;
        }

        public IPromise<TbxLogin> Login()
        {
            var loginParms = new TbxNameValuePairList() {
                    { "username", username },
                    { "pass", password },
                    { "logident", TbxUtil.getLogIdentifier() }
                };

            return client.Transceive<TbxLogin>("?action=login", loginParms);
        }

        public IPromise<TbxChildInfo> GetChildInfo(TbxChild child)
        {
            return client.Transceive<TbxChildInfo>("?action=getChildInfo&childid=" + child.id);
        }

        public IPromise<bool> Expect(IPromise<string> promise, string expect, string message)
        {
            var retval = new Deferred<bool>();

            promise.Fail(retval.Reject).Done(str =>
            {
                if (str == expect)
                {
                    retval.Resolve(true);
                }
                else
                {
                    retval.Reject(new PromiseFailArgs(message + ": " + str + ", expecting " + expect, "no details"));
                }
            });

            return retval;
        }

        public IPromise<bool> CreateAppointment(TbxChild child, DateTime timestamp, TbxEventType eventType, string pickupBy, string owner)
        {
            // FIXME: The system only supports one appointment/day so: check for existing appointment before
            //        creating a new one

            var time = String.Format("{0:d02}{1:d02}", timestamp.Hour, timestamp.Minute);
            var date = String.Format("{0}/{1}-{2}", timestamp.Day, timestamp.Month, timestamp.Year);

            var createParms = new TbxNameValuePairList()
                {
                    { "childid", child.id.ToString() },
                    { "eventtransport", "0" },
                    { "eventpickup", pickupBy },
                    { "eventtypeid", ((int)eventType).ToString() },
                    { "eventdescription", "" },
                    { "eventbeforestarttime", time },
                    { "eventstarttime", time },
                    { "eventstartdate", date },
                    { "eventendtime", time },
                    { "eventenddate", date },
                    { "eventtype", "0" },
                    { "eventrulebyday", "0" },
                    { "eventignoreonholiday", "0" },
                    { "eventowner", owner }
                };

            var promise = client.TransceiveRaw("?action=createAppointment", createParms);
            return Expect(promise, "success", "Failed to create appointment");
        }

        public IPromise<bool> DeleteAppointment(TbxChild child, TbxAppointment appointment)
        {
            var deleteParms = new TbxNameValuePairList() {
                  { "childid", child.id.ToString() },
                  { "eventplannedid", appointment.id },
                  { "eventowner", "" }
                };

            var promise = client.TransceiveRaw("?action=deleteAppointment", deleteParms);
            return Expect(promise, "success", "Failed to delete appointment");
        }

        private IPromise<List<TbxSchoolClassChild>> GetPupilsInClass(string sfoId, TbxSchoolClass klass)
        {
            return client.Transceive<List<TbxSchoolClassChild>>(String.Format("?action=getChildrenInClass&sfoid={0}&groupid={1}", sfoId, klass.id));
        }

        private void GetPupilsInClasses(string sfoid, List<TbxSchoolClass> klasses, int ix, Deferred<List<TbxSchoolClass>> masterPromise)
        {
            if (ix < klasses.Count)
            {
                GetPupilsInClass(sfoid, klasses[ix]).Fail(masterPromise.Reject).Done(children =>
                {
                    klasses[ix].pupils = children;
                    GetPupilsInClasses(sfoid, klasses, ix + 1, masterPromise);
                });
            }
            else
            {
                masterPromise.Resolve(klasses);
            }
        }

#if false
        private void GetPupilsInClasses(string sfoId, List<TbxSchoolClass> classes, int ix, TbxDeferred<List<TbxSchoolClass>> promise)
        {
            if (ix >= classes.Count)
            {
                promise.Resolve(classes);
                return;
            }

            var klass = classes[ix];
            GetPupilsInClass(sfoId, klass).Done(lst => { klass.pupils = lst; GetPupilsInClasses(sfoId, classes, ix + 1, promise); }).Fail(promise.Reject);
        }
#endif

        public IPromise<List<TbxSchoolClass>> GetAllClasses(string sfoId)
        {
            var retval = new Deferred<List<TbxSchoolClass>>();

            client.Transceive<TbxGroupsAndClasses>(String.Format("?action=getAllGroupsClasses&sfoid={0}", sfoId)).Fail(retval.Reject).Done(gac =>
            {
                var klasses = gac.classes;
                GetPupilsInClasses(sfoId, klasses, 0, retval);
            });

            return retval;
        }
    }

}
